﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;


namespace DeviceServer
{
    /// <summary>
    /// 低压协议
    /// </summary>
    public class LowVoltage
    {
        #region Field
        private const int FAULT_POINT_COUNT = 8;//排故题数量
        private const int WIRING_COUT = 3;//接线题数量 
        private LvSite _site;
        List<int[]> _FPDefA, FPDefB;

        private Dictionary<DeviceType, Dictionary<int, List<WireItemScore>>> _wireitemscores;
        public decimal Score { get; set; }
        public Action<DeviceState> DeviceStateAction;
        public Action<decimal> SubmitAction;
        #endregion

        #region 初始化
        public LowVoltage(LvSite site)
        {
            InitWireScore();
            InitDefCase();
            _site = site;
        }

        /// <summary>
        /// 初始化 接线
        /// </summary>
        private void InitWireScore()
        {
            _wireitemscores = new Dictionary<DeviceType, Dictionary<int, List<WireItemScore>>>
            {
                {DeviceType.A, new Dictionary<int, List<WireItemScore>>()},
                {DeviceType.B, new Dictionary<int, List<WireItemScore>>()}
            };


            _wireitemscores[DeviceType.A][0] = new List<WireItemScore>()
            {
                new WireItemScore(WireName.dengpao, 8),
                new WireItemScore(WireName.button1, 7),
                new WireItemScore(WireName.button2, 7),
                new WireItemScore(WireName.EEmeter, 3),
            };
            _wireitemscores[DeviceType.A][1] = new List<WireItemScore>()
            {
                new WireItemScore(WireName.Zhenliuqi, 11),
                new WireItemScore(WireName.Zlqbutton,11),
                new WireItemScore(WireName.EEmeter, 3),
            };
            _wireitemscores[DeviceType.A][2] = new List<WireItemScore>()
            {
                new WireItemScore(WireName.updn1, 4),
                new WireItemScore(WireName.updn2, 4),
                new WireItemScore(WireName.slot1, 4),
                new WireItemScore(WireName.slot2, 4),
                new WireItemScore(WireName.gnd1, 3),
                new WireItemScore(WireName.gnd2, 3),
                new WireItemScore(WireName.EEmeter, 3),
            };

            _wireitemscores[DeviceType.B][0] = new List<WireItemScore>()
            {
                new WireItemScore(WireName.KM1, 6),
                new WireItemScore(WireName.Zhengled, 6),
                new WireItemScore(WireName.zzbutton, 5),
                new WireItemScore(WireName.gnd1, 5),
                new WireItemScore(WireName.CTransformer, 3),
            };
            _wireitemscores[DeviceType.B][1] = new List<WireItemScore>()
            {
                new WireItemScore(WireName.stopbutton, 4),
                new WireItemScore(WireName.Zhengled, 4),
                new WireItemScore(WireName.KM1, 4),
                new WireItemScore(WireName.gnd1, 5),
                new WireItemScore(WireName.zzbutton, 5),
                new WireItemScore(WireName.CTransformer, 3),
            };
            _wireitemscores[DeviceType.B][2] = new List<WireItemScore>()
            {
                new WireItemScore(WireName.KM2, 3),
                new WireItemScore(WireName.fanled, 3),
                new WireItemScore(WireName.stopbutton, 3),
                new WireItemScore(WireName.Zhengled, 2),
                new WireItemScore(WireName.KM1, 2),
                new WireItemScore(WireName.fzbutton, 3),
                new WireItemScore(WireName.zzbutton, 3),
                new WireItemScore(WireName.gnd1, 3),
                new WireItemScore(WireName.CTransformer, 3),
            };
        }
        /// <summary>
        /// 初始化故障点
        /// </summary>
        private void InitDefCase()
        {
            //A板8个故障点列表
            _FPDefA = new List<int[]>()
            {
                   new int[2]{26,46},
                   new int[2]{27,42},
                   new int[2]{12,52},
                   new int[2]{53,65},
                   new int[2]{40,17},
                   new int[2]{24,33},
                    new int[2]{5,10},
                   new int[2]{17,29},
            };
            //B板8个故障点列表
            FPDefB = new List<int[]>()
            {
                new int[2] {1, 3},
                new int[2] {2, 4},
                new int[2] {9, 13},
                new int[2] {6, 15},
                new int[2] {29, 34},
                new int[2] {30, 39},
                new int[2] {100, 102},
                new int[2] {101, 103},
            };

        }
        #endregion

        #region 公共方法
        public string PaperToProtocal()
        {
            Paper paper = _site.Paper;
            DeviceType type = _site.DeviceType;
            string result = "", s = "";

            switch (type)
            {
                case DeviceType.A:
                case DeviceType.B:
                    result = "#";
                    break;
            }
            result += "0+";
            for (int i = 0; i < paper.FaultPoint.Length; i++)
            {
                if (paper.FaultPoint[i])
                {
                    s = (i + 1).ToString();
                    result += s + "+";
                }

            }
            result += "0+";
            switch (paper.Wiring)
            {
                case 0:
                    result += "11";
                    break;
                case 1:
                    result += "22";
                    break;
                case 2:
                    result += "33";
                    break;
            }
            //result = "#0+4+5+0+11";
            //Console.WriteLine("题目：" + result);
            return result;
        }

        public void Parse(string request)
        {

            if (request.IndexOf("jiaojuan") > 0)
            {
                Jiaojuan(_site);
            }

            //排故题
            Match match = Regex.Match(request, @"([@, #])(\d+)\+(\d+)\-(\d+)\+(\d+)");
            while (match.Success)
            {
                int v1, v2, v3, v4;
                int.TryParse(match.Groups[2].Value, out v1);
                int.TryParse(match.Groups[3].Value, out v2);
                int.TryParse(match.Groups[4].Value, out v3);
                int.TryParse(match.Groups[5].Value, out v4);
                int fpoint_index = FaultPoint(v2, v3);
                if (fpoint_index < 255)
                {

                    var isRight = v4 == 1;
                    if (_site.Paper.FaultPoint[fpoint_index])//故障点=true
                    {
                        _site.Answer.FaultPoint[fpoint_index] = isRight;
                    }
                    else
                    {
                        _site.Answer.FaultPoint[fpoint_index] = true; //答的题=true
                    }
                }

                match = match.NextMatch();
            }

            match = Regex.Match(request, @"(onoff|shunxu|switch2)\+([0,1])");
            while (match.Success)
            {
                int v;
                int.TryParse(match.Groups[2].Value, out v);
                Swtich(match.Groups[1].Value, v); //给开关answer赋值
                match = match.NextMatch();
            }

            match = Regex.Match(request, @"Fuse\+([0,1])");
            while (match.Success)
            {
                Fuse(int.Parse(match.Groups[1].Value));
                match = match.NextMatch();
            }



            match = Regex.Match(request, @"(stopbutton|Zhengled|KM1|KM2|fanled|dengpao|button1|button2|Zhenliuqi|dankai1|dankai2|updn1|updn2|Zlqbutton|slot1|slot2|gnd1|gnd2|zzbutton|fzbutton)\+(\d)");
            while (match.Success)
            {
                int v;
                int.TryParse(match.Groups[2].Value, out v);
                Wire(match.Groups[1].Value, v == 1);
                match = match.NextMatch();
            }

            match = Regex.Match(request, @"[@, #](\d+)\+over");
            if (match.Success)
            {
                int v;
                int.TryParse(match.Groups[1].Value, out v);
                Over(v);
            }

            match = Regex.Match(request, @"[@, #](\d+)Unreset");
            if (match.Success)
            {
                int v;
                int.TryParse(match.Groups[1].Value, out v);
                Console.WriteLine("未重置！");
                DeviceStateAction(DeviceState.unreset);
            }

            match = Regex.Match(request, @"#Sendok");
            if (match.Success)
            {
                DeviceStateAction(DeviceState.examing);
            }

            if (request.IndexOf("jiaojuan") > 0)
            {
                decimal faultpointscore = 0;
                decimal wiringscore = 0;
                Dictionary<string, decimal> compose = new Dictionary<string, decimal>();
                //算分
                Score = CalcScore(ref faultpointscore, ref wiringscore, ref compose);
                Score = Math.Floor(Score);
                DeviceStateAction(DeviceState.free);
                SubmitAction(Score);
            }

        }
        #endregion



        #region 解析数据
        private void Jiaojuan(LvSite site)
        {
            for (int i = 0; i < site.Answer.FaultPoint.Length; i++)
            {
                site.Answer.FaultPoint[i] = false;
            }
        }

        private int FaultPoint(int p1, int p2)
        {
            int result = 255; //预置为错误码。
            switch (_site.DeviceType)
            {
                case DeviceType.A:
                    for (int i = 0; i < FAULT_POINT_COUNT; i++)
                    {
                        if (_FPDefA[i].Contains(p1) && _FPDefA[i].Contains(p2))
                        {
                            result = i;
                            break;
                        }
                    }
                    break;
                case DeviceType.B:
                    for (int i = 0; i < FAULT_POINT_COUNT; i++)
                    {
                        if (FPDefB[i].Contains(p1) && FPDefB[i].Contains(p2))
                        {
                            result = i;
                            break;
                        }
                    }
                    break;
            }

            return result;
        }
        private void Over(int orderNr)
        {
            //Console.WriteLine("工位:" + orderNr);
        }

        private void Wire(string name, bool isRight)
        {
            //Console.WriteLine("接线题" + name);

            //对保险丝来说，对错判断是反的
            if (name == "Fuse")
                isRight = !isRight;
            WireName wireName = (WireName)Enum.Parse(typeof(WireName), name);
            foreach (var item in _site.Answer.Wiring.Keys)
            {
                if (item == wireName)
                {
                    _site.Answer.Wiring[item] = isRight;
                    break;
                }
            }
        }

        private void Swtich(string name, int value)
        {
            if (name == "onoff")
            {
                _site.Answer.Onoff = value == 0;
            }
            else if (name == "shunxu")
            {
                _site.Answer.Shunxu = value == 1;
            }
            else if (name == "switch2")
            {
                _site.Answer.Switch2 = value == 1;
            }
            else
            {
                Console.WriteLine("未知的开关名：" + name);
            }
        }

        private void Fuse(double v)
        {
            _site.Answer.Fuse = v == 1;
        }
        #endregion

        #region 计算分值
        private decimal CalcScore(ref decimal faultpointscore, ref decimal wiringscore, ref Dictionary<string, decimal> compose)
        {
            CalcFaultPointScore(ref faultpointscore, ref compose);
            var wireItemScores = _wireitemscores[_site.DeviceType][_site.Paper.Wiring];
            CalcWireScore(wireItemScores, ref wiringscore, ref compose);
            CalcSwitch(ref faultpointscore, ref wiringscore, ref compose);
            
            if (wiringscore < 0)
                wiringscore = 0;
            if (faultpointscore < 0)
                faultpointscore = 0;

            decimal result = faultpointscore + wiringscore;

            if (_site.Answer.Fuse)
            {
                compose.Add("保险丝", -result);
                result = 0;
            }
            
            return result;
        }

        private void CalcSwitch(ref decimal faultpointscore, ref decimal wiringscore, ref Dictionary<string, decimal> compose)
        {
            switch (_site.DeviceType)
            {
                case DeviceType.A:
                    if (_site.Answer.Onoff)
                    {
                        if (!_site.Answer.Shunxu)//4-28
                        {
                            wiringscore -= 20;
                            compose.Add("排故题开关", -20);
                        }
                    }
                    else
                    {
                        wiringscore -= 20;
                        compose.Add("排故题开关", -20);
                    }

                    if (!_site.Answer.Switch2)
                    {
                        faultpointscore -= 10;
                        compose.Add("接线题开关", -10);
                    }
                    break;
                case DeviceType.B:
                    if (_site.Answer.Onoff)
                    {
                        if (!_site.Answer.Shunxu)
                        {
                            faultpointscore -= 10;
                            compose.Add("B板开关", -10);
                        }
                    }
                    else
                    {
                        faultpointscore -= 10;
                        compose.Add("B板开关", -10);
                    }

                    if (!_site.Answer.Switch2)
                    {
                        wiringscore -= 20;
                        compose.Add("B板开关.Switch2", -20);
                    }
                    break;
            }
        }

        private void CalcWireScore(List<WireItemScore> wireItemScores, ref decimal score, ref Dictionary<string, decimal> compose)
        {
            foreach (var key in _site.Answer.Wiring.Keys)
            {
                var wireItemscore = wireItemScores.SingleOrDefault(i => i.WireName == key);
                if (wireItemscore != null && _site.Answer.Wiring[key])
                {
                    score += wireItemscore.Score;
                    compose.Add(key.ToString(), wireItemscore.Score);
                }
            }
        }



        /// <summary>
        /// 计算故障点分数
        /// </summary>
        /// <param name="faultpointscore"></param>
        /// <param name="compose"></param>
        private void CalcFaultPointScore(ref decimal faultpointscore, ref Dictionary<string, decimal> compose)
        {
            for (int i = 0; i < _site.Paper.FaultPoint.Length; i++)
            {
                //如果该故障点是需要考生解答的
                if (_site.Paper.FaultPoint[i])
                {
                    if (_site.Answer.FaultPoint[i])
                    {
                        faultpointscore += _site.Paper.FaultPointScore[i];
                        compose.Add("故障点" + i, _site.Paper.FaultPointScore[i]);
                    }
                }
                else
                {
                    if (_site.Answer.FaultPoint[i])
                    {
                        faultpointscore += _site.Paper.FaultPointScore[i];
                        compose.Add("故障点" + i, _site.Paper.FaultPointScore[i]);
                    }
                }
            }
        }
        #endregion

    }

    /// <summary>
    /// 试卷
    /// </summary>
    public class Paper
    {
        /// <summary>
        /// 排故题的八个故障点，置为true表示出那道题
        /// </summary>
        public bool[] FaultPoint { get; set; }

        /// <summary>
        /// 接线题序号
        /// </summary>
        public int Wiring { get; set; }

        /// <summary>
        /// 排故题分值
        /// </summary>
        public decimal[] FaultPointScore { get; set; }
        /// <summary>
        /// 接线题 分值
        /// </summary>
        public int WiringScore { get; set; }
    }

    /// <summary>
    /// 答案
    /// </summary>
    public class Answer
    {
        public Answer()
        {
            this.FaultPoint = new bool[8];
            this.Wiring = new Dictionary<WireName, bool>();
        }
        /// <summary>
        /// 接线部分的开关对错
        /// </summary>
        public bool Switch2 { get; set; }
        /// <summary>
        /// 排故的两个开关对错
        /// </summary>
        public bool Onoff { get; set; }
        /// <summary>
        /// 排故的两个开关对错
        /// </summary>
        public bool Shunxu { get; set; }
        /// <summary>
        /// 保险丝
        /// </summary>
        public bool Fuse { get; set; }
        /// <summary>
        /// 排故题八个故障点的连接状态。
        /// </summary>
        public bool[] FaultPoint { get; set; }
        /// <summary>
        /// 接线
        /// </summary>
        public Dictionary<WireName, bool> Wiring { get; set; }
    }

   

    /// <summary>
    /// 接线题记录
    /// </summary>    
    class WireItemScore
    {
        /// <summary>
        /// 接线题名称
        /// </summary>
        public WireName WireName { get; set; }
        /// <summary>
        /// 分值
        /// </summary>
        public decimal Score { get; set; }

        public WireItemScore(WireName wireName, decimal score)
        {
            WireName = wireName;
            Score = score;
        }
    }

 

    /// <summary>
    /// 低压板子类型
    /// </summary>
    public enum DeviceType
    {
        A,
        B
    }
    /// <summary>
    /// 接线题名称
    /// </summary>
    public enum WireName
    {
        stopbutton, Zhengled, KM1, KM2, fanled, dengpao, button1, button2,
        Zhenliuqi, dankai1, dankai2, Zlqbutton, slot1, slot2, updn1, updn2, gnd1, gnd2, zzbutton, fzbutton
            , EEmeter, CTransformer, Fuse
    }
}
 
